/******************************************************************************
 *
 * MantaFlow fluid solver framework
 * Copyright 2011 Tobias Pfaff, Nils Thuerey 
 *
 * This program is free software, distributed under the terms of the
 * Apache License, Version 2.0 
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Basic quaternion class
 *
 ******************************************************************************/

#ifndef _QUATERNION_H
#define _QUATERNION_H

#include "vectorbase.h"

namespace Manta {

//! Very basic quaternion class
class Quaternion {
public:
    
    //! default constructor
    Quaternion() : x(0), y(0), z(0), w(0) {}
    
    //! copy constructor
    Quaternion(const Quaternion& q) : x(q.x), y(q.y), z(q.z), w(q.w) {}
    
    //! construct a quaternion from members
    Quaternion(Real _x, Real _y, Real _z, Real _w) : x(_x), y(_y), z(_z), w(_w) {}
        
    //! construct a quaternion from imag/real parts
    Quaternion(Vec3 i, Real r) : x(i.x), y(i.y), z(i.z), w(r) {}
    
    //! Assign operator
    inline Quaternion& operator= (const Quaternion& q) {
        x = q.x;
        y = q.y;
        z = q.z;
        w = q.w;
        return *this;
    }
    
    //! Assign multiplication operator
    inline Quaternion& operator*= ( const Real a ) {
        x *= a;
        y *= a;
        z *= a;
        w *= a;
        return *this;
    }
    
    //! return inverse quaternion
    inline Quaternion inverse() const {
        Real mag = 1.0/(x*x+y*y+z*z+w*w);
        return Quaternion(-x*mag,-y*mag,-z*mag,w*mag);
    }
    
    //! imaginary part accessor
    inline Vec3 imag() { return Vec3(x,y,z); }

    // imaginary part
    Real x;
    Real y;
    Real z;
    
    // real part
    Real w;    
};


//! Multiplication operator
inline Quaternion operator* ( const Quaternion &q1, const Quaternion &q2 ) {
    return Quaternion ( q2.w * q1.x + q2.x * q1.w + q2.y * q1.z - q2.z * q1.y,
                        q2.w * q1.y + q2.y * q1.w + q2.z * q1.x - q2.x * q1.z,
                        q2.w * q1.z + q2.z * q1.w + q2.x * q1.y - q2.y * q1.x,
                        q2.w * q1.w - q2.x * q1.x - q2.y * q1.y - q2.z * q1.z );
}

//! Multiplication operator
inline Quaternion operator* ( const Quaternion &q, const Real a ) {
    return Quaternion ( q.x*a, q.y*a, q.z*a, q.w*a);
}

} // namespace

#endif
